#include "KeyRecommander.h"
#include <iostream>
#include<nlohmann/json.hpp>
#include<sstream>

using std::cout;
using std::ostringstream;


int getbytenum_utf8(char byte)
{
    int bytenum = 0;
    for (int i = 0; i < 6; ++i)
    {
        if (byte & (1 << (7 - i)))
        {
            ++bytenum;
        }
        else
            break;
    }
    return bytenum = bytenum == 0 ? 1 : bytenum;
}

KeyRecommander::KeyRecommander(Dictionary* dict)
    :_dict(dict)
{
}

KeyRecommander::KeyRecommander(string &query, Dictionary *dict)
    : _sought(query), _dict(dict)
{
}

    nlohmann::json KeyRecommander::recommand(string& req)
{
    _sought = req;
    execute();
return     response();
}

//获取索引
void KeyRecommander::execute()
{

    map<string, set<int>> map = _dict->queryIndex();
    set<int> setINdex;
    for (size_t i = 0; i < _sought.size(); ++i)
    {
        int ret = getbytenum_utf8(_sought[i]);
        string buf = _sought.substr(i, ret);
        for (auto &i : map[buf])
        {
            setINdex.insert(i);
        }
    }
    statistic(setINdex);
}

void KeyRecommander::queryIndexTable()
{

}

int triple_min(const int &a, const int &b, const int &c)
{
    // return a < b ? (a < c ? a : c) : (b < c ? b : c);
    int temp = a;
    if (temp > b)
    {
        temp = b;
    }
    if (temp > c)
    {
        temp = c;
    }
    return temp;
}

size_t length(const string &str)
{
    size_t ilen = 0;
    for (size_t idx = 0; idx < str.size(); ++idx)
    {
        int nBytes = getbytenum_utf8(str[idx]);
        idx += (nBytes - 1);
        ++ilen;
    }
    return ilen;
}

void KeyRecommander::statistic(set<int> &iset)
{
    //拿出候选索引对应的词
    vector<std::pair<string, int>> vec = _dict->getVector();
    for (auto &i : iset)
    {
        string str = vec[i].first;
        int ret = distance(str);
        Candidate tmp(str, vec[i].second, ret);
        _result.push(tmp);
    }
}
int KeyRecommander::distance(const string &rhs)
{ // 计算最小编辑距离-包括处理中英文
    size_t lhs_len = length(_sought);
    size_t rhs_len = length(rhs);
    int editDist[lhs_len + 1][rhs_len + 1];
    for (size_t idx = 0; idx <= lhs_len; ++idx)
    {
        editDist[idx][0] = idx;
    }
    for (size_t idx = 0; idx <= rhs_len; ++idx)
    {
        editDist[0][idx] = idx;
    }
    std::string sublhs, subrhs;
    for (std::size_t dist_i = 1, lhs_idx = 0; dist_i <= lhs_len; ++dist_i,
                     ++lhs_idx)
    {
        size_t nBytes = getbytenum_utf8(_sought[lhs_idx]);
        sublhs = _sought.substr(lhs_idx, nBytes);
        lhs_idx += (nBytes - 1);
        for (std::size_t dist_j = 1, rhs_idx = 0;
             dist_j <= rhs_len; ++dist_j, ++rhs_idx)
        {
            nBytes = getbytenum_utf8(rhs[rhs_idx]);
            subrhs = rhs.substr(rhs_idx, nBytes);
            rhs_idx += (nBytes - 1);
            if (sublhs == subrhs)
            {
                editDist[dist_i][dist_j] = editDist[dist_i - 1][dist_j -
                                                                1];
            }
            else
            {
                editDist[dist_i][dist_j] =
                    triple_min(editDist[dist_i][dist_j - 1] + 1,
                               editDist[dist_i - 1][dist_j] + 1,
                               editDist[dist_i - 1][dist_j - 1] + 1);
            }
        }
    }
    return editDist[lhs_len][rhs_len];
}

    nlohmann::json KeyRecommander::response()
    {
        int i=0;
        vector<string> vec;
        while(!_result.empty())
        {
            if(vec.size()<10)
            {
            ostringstream oss;
            oss<<_result.top();
            vec.push_back(oss.str());
            // cout<<oss.str()<<"\n";
            _result.pop();
            ++i;
            }
            else{
            _result.pop();
            }
        }
        nlohmann::json json=vec;
        for(auto&i: json.items())
        {
            cout<<i.key()<<" "<<i.value()<<"\n";
        }
        return json;
    }
